package net.whzjkj.gateway.core.util;

import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;
import java.util.List;

/**
 * @description: byte工具类
 * @author: Mr.Hu
 * @create: 2018-10-31 14:37
 **/
@Slf4j
public class ByteUtils {

    public static int byteToInteger(byte[] data) {
        int res;
        if (data.length==1){
            res =  oneByteToInteger(data[0]);
        }else if (data.length==2){
            res = twoBytesToInteger(data) ;
        }else if (data.length==3){
            res = threeBytesToInteger(data) ;
        }else{
            res = fourBytesToInteger(data);
        }
        return res;
    }

    /**
     * 把一个byte转化位整形,通常为指令用
     *
     * @param value
     * @return
     * @throws Exception
     */
    public static int oneByteToInteger(byte value) {
        return (int) value & 0xFF;
    }

    /**
     * 把一个2位的数组转化位整形
     *
     * @param value
     * @return
     * @throws Exception
     */
    public static int twoBytesToInteger(byte[] value) {
        // if (value.length < 2) {
        // throw new Exception("Byte array too short!");
        // }
        int temp0 = value[0] & 0xFF;
        int temp1 = value[1] & 0xFF;
        return ((temp0 << 8) + temp1);
    }

    /**
     * 把一个3位的数组转化位整形
     *
     * @param value
     * @return
     * @throws Exception
     */
    public static int threeBytesToInteger(byte[] value) {
        int temp0 = value[0] & 0xFF;
        int temp1 = value[1] & 0xFF;
        int temp2 = value[2] & 0xFF;
        return ((temp0 << 16) + (temp1 << 8) + temp2);
    }

    /**
     * 把一个4位的数组转化位整形,通常为指令用
     *
     * @param value
     * @return
     * @throws Exception
     */
    public static int fourBytesToInteger(byte[] value) {
        // if (value.length < 4) {
        // throw new Exception("Byte array too short!");
        // }
        int temp0 = value[0] & 0xFF;
        int temp1 = value[1] & 0xFF;
        int temp2 = value[2] & 0xFF;
        int temp3 = value[3] & 0xFF;
        return ((temp0 << 24) + (temp1 << 16) + (temp2 << 8) + temp3);
    }

    public static int mathCheckCode(byte[] msg, int startIndex, int length) {
        int checkCode = 0;
        for (int i=0;i<length;i++){
            checkCode ^=msg[i];
        }
        return checkCode;
    }

    /**
     * 把一个整形该为1位的byte数组
     * @param i
     * @return
     */
    public static byte[] integerTo1Byte(int i) {
        return new byte[]{(byte) (i & 0xff)};
    }


    /**
     * 把一个整形改为2位的byte数组
     *
     * @param value
     * @return
     * @throws Exception
     */
    public static byte[] integerTo2Bytes(int value) {
        byte[] result = new byte[2];
        result[0] = (byte) ((value >>> 8) & 0xFF);
        result[1] = (byte) (value & 0xFF);
        return result;
    }

    /**
     * 把一个整形改为3位的byte数组
     *
     * @param value
     * @return
     * @throws Exception
     */
    public static byte[] integerTo3Bytes(int value) {
        byte[] result = new byte[3];
        result[0] = (byte) ((value >>> 16) & 0xFF);
        result[1] = (byte) ((value >>> 8) & 0xFF);
        result[2] = (byte) (value & 0xFF);
        return result;
    }

    /**
     * 把一个整形改为4位的byte数组
     *
     * @param value
     * @return
     * @throws Exception
     */
    public static byte[] integerTo4Bytes(int value){
        byte[] result = new byte[4];
        result[0] = (byte) ((value >>> 24) & 0xFF);
        result[1] = (byte) ((value >>> 16) & 0xFF);
        result[2] = (byte) ((value >>> 8) & 0xFF);
        result[3] = (byte) (value & 0xFF);
        return result;
    }

    /**
     * 把一个整形该为2位的byte数组
     * @param i
     * @return
     */
    public static byte[] integerTo2Byte(int i) {
        byte[] b = new byte[2];
        b[0] = (byte) ((i >>> 8) & 0xff);
        b[1] = (byte)(i & 0xff);
        return b;
    }

    /**
     * 合并字节数组
     * @param first
     * @param rest
     * @return
     */
    public static byte[] concatBytes(byte[] first, byte[] ... rest) {
        int totalLength = first.length;
        for (byte[] array : rest) {
            if (array != null) {
                totalLength += array.length;
            }
        }
        byte[] result = Arrays.copyOf(first, totalLength);
        int offset = first.length;
        for (byte[] array : rest) {
            if (array != null) {
                System.arraycopy(array, 0, result, offset, array.length);
                offset += array.length;
            }
        }
        return result;
    }

    /**
     * 合并字节数组
     *
     * @param rest
     * @return
     */
    public static byte[] concatBytes(List<byte[]> rest) {
        int totalLength = 0;
        for (byte[] array : rest) {
            if (array != null) {
                totalLength += array.length;
            }
        }
        byte[] result = new byte[totalLength];
        int offset = 0;
        for (byte[] array : rest) {
            if (array != null) {
                System.arraycopy(array, 0, result, offset, array.length);
                offset += array.length;
            }
        }
        return result;
    }

    /**
     * 将byte转化我浮点数
     * @param bs
     * @return
     */
    public static float byte2Float(byte[] bs) {
        return Float.intBitsToFloat(
                (((bs[3] & 0xFF) << 24) + ((bs[2] & 0xFF) << 16) + ((bs[1] & 0xFF) << 8) + (bs[0] & 0xFF)));
    }

    /**
     * BCD码转String
     * @param data
     * @param startIndex
     * @param length
     * @return
     */
    public static String parseStringFromBCDBytes(byte[] data, int startIndex, int length) {
        return parseStringFromBCDBytes(data, startIndex, length, null);
    }

    /**
     * BCD码转String
     * @param data
     * @param startIndex
     * @param length
     * @param defaultVal
     * @return
     */
    public static String parseStringFromBCDBytes(byte[] data, int startIndex, int length, String defaultVal) {
        try {
            byte[] tmp = new byte[length];
            System.arraycopy(data, startIndex, tmp, 0, length);
            return BCD8421Utils.bcd2String(tmp);
        }catch (Exception e){
            e.printStackTrace();
            return defaultVal;
        }
    }

    public static int parseIntFromBytes(byte[] data, int startIndex, int length) {
        return parseIntFromBytes(data, startIndex, length, 0);
    }

    public static int parseIntFromBytes(byte[] data, int startIndex, int length, int defaultVal) {
        try {
            // 字节数大于4,从起始索引开始向后处理4个字节,其余超出部分丢弃
            final int len = length > 4 ? 4 : length;
            byte[] tmp = new byte[len];
            System.arraycopy(data, startIndex, tmp, 0, len);
            return ByteUtils.byteToInteger(tmp);
        }catch (Exception e){
            e.printStackTrace();
            return defaultVal;
        }
    }

    public float parseFloatFromBytes(byte[] data, int startIndex, int length) {
        return this.parseFloatFromBytes(data, startIndex, length, 0F);
    }

    private float parseFloatFromBytes(byte[] data, int startIndex, int length, float defaultVal) {
        try {
            // 字节数大于4,从起始索引开始向后处理4个字节,其余超出部分丢弃
            final int len = length > 4 ? 4 : length;
            byte[] tmp = new byte[len];
            System.arraycopy(data, startIndex, tmp, 0, len);
            return ByteUtils.byte2Float(tmp);
        } catch (Exception e) {
            log.error("解析浮点数出错:{}", e.getMessage());
            e.printStackTrace();
            return defaultVal;
        }
    }
}
